home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 June
/
EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso
/
earcd
/
arexx
/
rxdssppr.lha
/
rexxdossupport
/
txt
/
RexxDosSupport.mod
next >
Wrap
Text File
|
1996-03-20
|
49KB
|
1,546 lines
(*(***********************************************************************
:Program. rexxdossupport.mod
:Contents. access to V37+ Dos.library functions from within ARexx
:Author. hartmtut Goebel [hG]
:Address. Aufseßplatz 5, D-90459 Nürnberg
:Address. UseNet: hartmut@oberon.nbg.sub.org
:Copyright. Copyright © 1994-1996 by hartmtut Goebel
:Language. Oberon-2
:Translator. Amiga Oberon 3.11
:Imports. Printf (Martin Horneffer), RxLibsSupport [hG]
:Version. $VER: rexxdossupport.mod 3.4 (20.3.96) Copyright © 1994-1996 by hartmtut Goebel
(* $StackChk- $NilChk- $RangeChk- $CaseChk- $OvflChk- $ReturnChk- $ClearVars- *)
(****** rexxdossupport.library/--history-- **********************
*
*
* 3.4 20 Mar 1996
* · fixed FilePart(): last charakter has been stripped
* (ack: Nick Ring)
* 3.3 06 Mar 1996
* · revised autodocs a bit
* 3.2 23 Feb 1996
* · improofed docs about accessing local environment varibales
* · fixed some erratas
* 3.1 16 Feb 1996
* · new functions: AddPart(), FilePart(), PathPart()
* (suggested many times)
* · ReadArgs supports /T now (suggested by Magnus Holgren)
* 3.0 17 Jan 1996 [Kai Bolay]
* · new function: AbsolutePath()
*
* 2.4 11 Oct 1995
* · fixed memory lose in ReadArgs (ack: Alexander Stirmlinger)
* · ReadArgs example is now complete (ack: Oliver Creighton)
* 2.3 01 Apr 1995
* · fixed problem with synonyms: foo=bar lead to illegal
* variable named 'FOO=BAR'. Now allways th first synonym is
* taken as var-name.
* 2.2 18 Jul 1994
* · Shame on me! library names must be lowercase
* · Some more notes in documentation
* 2.1 03 Jun 1994
* · removed curious bug in ReadArgs() (uninitialized var,
* introduced in V2.0)
* 2.0 07 May 1994 (never released)
* · stronger check for present args to avoid NIL-Traps
* · new functions: Delete(), Rename(), MakeDir(),
* SetComment(), SetProtection()
* 1.4 01 Feb 1994
* · only significant part of parsed pattern is copied
* into the ARexx Argstring
* 1.3 23 Jan 1994
* · uses module RxLibsSupport [hG]
* 1.2 18 Jan 1994
* · finished dokumentation
* · UnsetVar() - like shell commnad - renamed to
* DeleteVar() - like in dos.library
* · SetVar() no longer accepts option "Binary"
* 1.1 16 Jan 1994
* initial release
*
*******
(****** rexxdossupport.library/--Disclaimer-- **********************
*
*Disclaimer
*----------
*
* Permission is granted to make and distribute verbatim copies of this
*manual provided the copyright notice and this permission notice are
*preserved on all copies.
*
*COPYRIGHT
*
* Copyright (C) 1994-1996 by hartmut Goebel
*
* No program, document, data file or source code from this software
*package, neither in whole nor in part, may be included or used in other
*software packages unless it is authorized by a written permission from
*the author.
*
*
*NO WARRANTY
*
* There is no warranty for this software package. Although the author
*has tried to prevent errors, he can't guarantee that the software package
*described in this document is 100% reliable. You are therefore using this
*material at your own risk. The author cannot be made responsible for any
*damage which is caused by using this software package.
*
*
*DISTRIBUTION
*
* This software package is freely distributable. It may be put on any
*media which is used for the distribution of free software, like Public
*Domain disk collections, CDROMs, FTP servers or bulletin board systems.
*
* In order to ensure the integrity of this software package,
*distributors should use the original archive file rexxdossuppor.lha.
*The author cannot be made responsible if this software package has
*become unusable due to modifications of the archive contents or of
*the archive file itself.
*
* There is no limit on the costs of the distribution, e.g. for the
*media, like floppy disks, streamer tapes or compact disks, or the process
*of duplicating. Such limits have been proven to be harmful to the idea of
*freely distributable software, e.g. instead of reducing the price of the
*floppy disk below the limit, the software was simply removed from the
*master disk.
*
* Although the author does not impose any limit on the distribution of
*this software package, he would like to express his personal opinions on
*this matter:
*
* * This software package should be made available to everyone free of
* charge whenever it is possible.
*
* * If you have acquired this software package under normal conditions
* from a Public Domain dealer on a floppy disk at a price higher than
* 5DM or US $5, then you have definitely paid too much. Please don't
* support this improper profit making any longer and switch to a
* cheaper source as soon as possible.
*
*
*USAGE RESTRICTIONS
*
* No program, document, data file or source code from this software
*package, neither in whole nor in part, may be used on any machine which
*is used
*
* * for the research, development, construction, testing or production
* of weapons or other military applications. This also includes any
* machine which is used in the education for any of the above
* mentioned purposes.
*
* * by people who accept, support or use violence against other people,
* e.g. citizens from foreign countries.
*
*********)*)*)*)
(****** rexxdossupport.library/--background-- *******************
*
* rexxdossupport.library 3.4
* ==========================
*
* Copyright (C) 1994-1996 by hartmut Goebel
*
*
* After programming ARexx script for quite a while, I missed some
* function found in dos.library -- especially access to
* environment variables and the comfortable argument parsing. Since
* there seamed to be no ARexx function library which implements
* this functions, I decited to write my own. And here it is.
*
* This are the functions handled by this library.
* · ReadArgs()
* · GetVar(), SetVar(), DeleteVar()
* · ParsePattern(), MatchPattern() - even case-insensitive
* · Fault()
* · Delete(), Rename(), MakeDir()
* · SetComment(), SetProtection()
* · FilePart(), PathPart(), AddPart()
*
* This additional functions have been added for your convinience:
* · AbsolutePath()
*
* Enjoy it!
* +++hartmut
*
*********)
(****** rexxdossupport.library/--installation-- *******************
*
* To use rexxdossupport.library, just copy is to yout LIBS:
* directory. That's all.
*
* The LVO for the ARexx-Dispatcher is -30.
* NB: it's the only LVO for this library :-)
*
* So, in every ARexx-Script you want to use rexxdossupport.library,
* insert
*
* call addlib("rexxdossupport.library",0,-30,2)
*
* somewhere before the first call to one of the routines
* implemented in this library.
* Since ARexx does not check whether the lib can be opened but only
* inserts the name into a list, the result value from addlib() can
* be ignored in most cases. The value would be interesting to check
* if the added note will require the same library version, but I
* don't know how to find this out.
*
*********)
MODULE rexxdossupport;
(* $StackChk- $ClearVars- *)
IMPORT
d := Dos,
e := Exec,
str := Strings,
ol := OberonLib,
pf := Printf,
PointerArithmetics,
rx := Rexx,
rxs := RexxSysLib,
rvi := RVI,
rls := RxLibsSupport,
y := SYSTEM;
CONST
versionString = "$VER: rexxdossupport 3.4 (20.3.96) Copyright © 1994-1996 by hartmtut Goebel";
progNotFound = rls.progNotFound;
noMemory = rls.noMemory;
badNumArgs = rls.badNumArgs;
stringTooLong= rx.err10009;
funcErr = rx.err10012;
invalidArg = rx.err10018;
nestingLevel = rx.err10043;
invalidTemplate = rx.err10037;
errorReturnFromFunc = rx.err10012;
arithConvertionErr = rx.err10047;
strTRUE = rls.strTRUE;
strFALSE = rls.strFALSE;
PROCEDURE ^ GetVar (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ SetVar (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ DeleteVar (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ MatchPattern (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ ParsePattern (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ Fault (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ ReadArgs (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
(* new for V2.0 *)
PROCEDURE ^ Delete (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ Rename (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ MakeDir (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ SetComment (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ SetProtection (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
(* new for v3.0 *)
PROCEDURE ^ AbsolutePath (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
(* new for v3.1 *)
PROCEDURE ^ FilePart (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ PathPart (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
PROCEDURE ^ AddPart (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
CONST
numFunctions = 16;
TYPE
FunctionList = ARRAY numFunctions OF rls.FunctionListEntry;
CONST
functionList = FunctionList(
y.ADR("GetVar"),1,3,GetVar,
y.ADR("SetVar"),2,3,SetVar,
y.ADR("DeleteVar"),1,2,DeleteVar,
y.ADR("MatchPattern"),2,4,MatchPattern,
y.ADR("ParsePattern"),1,2,ParsePattern,
y.ADR("Fault"),1,2,Fault,
y.ADR("ReadArgs"),2,3,ReadArgs,
y.ADR("Delete"),1,1,Delete,
y.ADR("Rename"),2,2,Rename,
y.ADR("SetComment"),2,2,SetComment,
y.ADR("SetProtection"),2,2,SetProtection,
y.ADR("MakeDir"),1,1,MakeDir,
y.ADR("AddPart"),2,2,AddPart,
y.ADR("FilePart"),1,1,FilePart,
y.ADR("PathPart"),1,1,PathPart,
y.ADR("AbsolutePath"),1,1,AbsolutePath
);
(* ---------------------------------------------------------------- *)
(****** rexxdossupport.library/ReadArgs ***************
*
* NAME
* ReadArgs -- Parse argument string using Dos/ReadArgs()
*
* SYNOPSIS
* okay = ReadArgs( arguments, template, [stem] )
*
* FUNCTION
* Parses an argument string according to a template. See
* dos.library/ReadArgs() for details and describtion of the
* template.
*
* This function supports the following template options:
*
* /S - Switch. Resulting variable will be either true (1) or
* false (0).
* /T - Toggle. (V3) Results like /S, but much more mighty,
* see below.
* /N - Number.
* /M - Multiple strings. See below for further information.
*
* /K - Keyword. }
* /A - Required. } handled by dos
* /F - Rest of line. }
*
* INPUTS
* arguments - the string to be parsed
* template - dos.library/ReadArgs()-style like template
* stem - stem prefix for resulting variables (optional)
*
* For /T arguments the corresponding variable (see RESULTS) is read
* to get the default. The variable must be either false (0) or true
* (1). If the variable does not exist, the default is false (0).
*
* RESULT
* okay - boolean value indicating success.
*
* RC (rexx variable) - contains the dos error code if the
* function was not successfull. This can can directly
* be used as input for Fault().
*
* For each item in the template which has a corresponding
* argument, a Rexx variable will be created. The variable's
* name is the item's name prefixed by the stem name (if given). If
* an item name has synonyms, the first one will be taken as variable
* name.
*
* Items with option /M will result in a stem variable with a
* .COUNT node containing the number of elements. If no fitting
* arguments is passed, .COUNT will be zero.
* The entries will be in stem nodes .0 to .n (where n is
* .COUNT-1).
*
* EXAMPLE
* /* ReadArgsExample.rexx */
* If ~show('L', 'rexxdossupport.library') then do
* if ~addlib('rexxdossupport.library', 0, -30, 2) then do
* say "rexxdossupport.library not available, exiting ..."
* exit 20
* end
* end
*
* parse arg args /* get the arguments w/o ARexx-Parsing */
*
* template = "Files/M,Method/K,MinSize/K/N,Test/S,Toggle/T"
*
* /* set defaults */
* Method = "NUKE"; MinSize = 512;
*
* /* no stem given: results are assigned to simple variables */
*
* if ReadArgs(args,template) then
* say 'Method='method ' MinSize='MinSize 'Test=' test 'Toggle='toggle
* do i = 0 by 1 for files.count
* say files.i
* end
*
* /* stem given: results are assigned to stem variable */
* /* since the default values are set as non-stem variables,
* * they are not overwritten by the following call even if
* * given
* */
*
* drop method MinSize test /*toggle is kept! */
*
* if ReadArgs(args,template,"args.") then
* say 'Method ='args.method 'MinSize='args.MinSize
* say 'Test=' args.test 'Toggle='args.toggle
* do i = 0 by 1 for args.files.count
* say args.files.i
* end
*
* NOTE
* /T was unsupported till V 3.1
*
* NOTE
* Some background about /T which is not documented well:
* /T acts very like /S but may be set to on/off using the keywords
* 'YES'/'ON' and 'NO'/'OFF'. This is usefull when parsing eg.
* tool-types or using multible option-sources (eg. defaults taken
* from an environment variable).
*
* /S /T
* 1st option-set UseScreen UseScreen=YES
* 2nd option-set NoUseScreen UseScreen=NO
* --> results into ??confusion?? UseScreen=NO
*
* SEE ALSO
* Fault(), dos.library/ReadArgs()
*
***********************)
PROCEDURE ReadArgs (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
TYPE ArgsArray = UNTRACED POINTER TO ARRAY d.maxMultiArgs+1 OF LONGINT;
PROCEDURE CreateSTEM (msg: rx.RexxMsgPtr;
template: e.LSTRPTR;
resarray: ArgsArray;
stembase: e.STRPTR;
setDefaultsFromRexxVars: BOOLEAN): INTEGER;
VAR
synonym, result, rs, rb, t, wordCnt: INTEGER;
opts, optn, optm, optt: BOOLEAN;
longbuff: rls.ConvertLongBuffer;
resb: ARRAY 512 OF CHAR;
PROCEDURE SetValue (VAR value: LONGINT): INTEGER;
VAR
string: e.LSTRPTR;
BEGIN
IF optt THEN (*$RangeChk-*)
result := SHORT(rvi.GetRexxVar(msg,resb,string)); (*$RangeChk=*)
IF result # rx.ok THEN RETURN result END;
value := d.DOSFALSE;
IF string # NIL THEN
IF d.StrToLong(string^,value) < 0 THEN RETURN arithConvertionErr END;
CASE value OF
|0: (*value := d.DOSFALSE; alredy set *)
|1: value := d.DOSTRUE;
ELSE RETURN arithConvertionErr
END;
END;
END;
RETURN rx.ok;
END SetValue;
PROCEDURE GetValue (value: LONGINT): INTEGER;
VAR
string: e.LSTRPTR;
BEGIN
IF opts OR optt THEN
IF value = d.DOSFALSE THEN string := y.ADR(strFALSE);
ELSE string := y.ADR(strTRUE); END;
ELSIF optn THEN (* numerisch *)
pf.OSPrintF(longbuff, "%ld", y.VAL(ArgsArray,value)[0]);
string := y.ADR(longbuff);
ELSE (* string *)
string := y.VAL(e.LSTRPTR,value);
END; (*$RangeChk-*)
RETURN SHORT(rvi.SetRexxVar(msg,resb,string^,str.Length(string^))); (*$RangeChk=*)
END GetValue;
PROCEDURE CreateResultList(value: ArgsArray): INTEGER;
VAR
index: LONGINT;
tt: e.STRPTR;
result: INTEGER;
BEGIN
tt := y.ADR(resb[t]);
index := 0;
IF value # NIL THEN
WHILE value[index] # NIL DO
pf.OSPrintF( tt^, ".%ld", index); (* Index an den Stem-Namen anhängen *)
result := GetValue(value[index]);
IF result # 0 THEN RETURN result; END;
INC(index);
END;
END;
tt^ := ".COUNT"; (* Die Count-Node ausfüllen *)
pf.OSPrintF( longbuff, "%ld", index ); (*$RangeChk-*)
RETURN SHORT(rvi.SetRexxVar(msg,resb,longbuff,str.Length(longbuff))); (*$RangeChk=*)
END CreateResultList;
BEGIN
wordCnt := 0; result := rx.ok;
IF stembase # NIL THEN (* Präfix einbauen *)
COPY(stembase^,resb); rb := SHORT(str.Length(resb));
str.Upper(resb);
ELSE
resb := ""; rb := 0;
END;
rs := 0;
(* Liste aufbauen *)
WHILE template[rs] # CHR(0) DO
t := rb; optn := FALSE; optm := FALSE; opts := FALSE; optt := FALSE; synonym := -1;
LOOP
CASE template[rs] OF
| CHR(0): EXIT;
| ",": INC(rs); EXIT;
| "=": synonym := t;
| "/":
INC(rs);
CASE CAP(template[rs]) OF
| "N": optn := TRUE;
| "M": optm := TRUE;
| "S": opts := TRUE;
| "T": optt := TRUE;
ELSE END;
ELSE
resb[t] := CAP(template[rs]); INC(t); (* Resultatnamen kopieren *)
END;
INC(rs);
END;
IF synonym >= 0 THEN t := synonym; END;
resb[t] := CHR(0);
IF opts OR optt THEN
optm := FALSE; optn := FALSE; END;
(* hier ist nun der Basisname der Stem-Variable in resb,
* und t zeigt in resb auf die Stelle, an der nun ggf. die
* Stem-Erweiterungen (.COUNT, .0 - .n) angehängt werden
*)
IF setDefaultsFromRexxVars THEN
result := SetValue(resarray[wordCnt]);
ELSIF optm THEN (* /M war im Namen, also Liste *)
result := CreateResultList(y.VAL(ArgsArray,resarray[wordCnt]));
ELSE (* keine Liste *)
IF opts OR optt OR (resarray[wordCnt] # NIL) THEN
result := GetValue(resarray[wordCnt]);
END;
END;
IF result # rx.ok THEN RETURN result; END;
INC(wordCnt);
END;
RETURN result;
END CreateSTEM;
VAR
hasOptT: BOOLEAN;
PROCEDURE ScanArgs(template: ARRAY OF CHAR): LONGINT; (* $CopyArrays- *)
VAR
pos, numArgs: LONGINT;
BEGIN
numArgs := 1; pos := 0;
WHILE pos < LEN(template) DO
CASE template[pos] OF
|0X: RETURN numArgs;
|",": INC(numArgs);
|"/": IF template[pos+1] = "T" THEN hasOptT := TRUE END;
ELSE END;
INC(pos);
END;
RETURN numArgs;
END ScanArgs;
CONST
rdArgsDefault = d.RDArgs(NIL,0,0, 0, NIL,0,NIL,LONGSET{d.noPrompt});
argInput = 1; argTemplate = 2; argStem = 3;
VAR
argv: UNTRACED POINTER TO d.ArgsStruct;
arguments, rdArgs: d.RDArgsPtr;
i: LONGINT;
retval: INTEGER;
input: e.LSTRPTR;
BEGIN (* ReadArgs *)
IF ~ rls.ArgsPresent(msg,1,2) THEN RETURN invalidArg; END;
IF (rx.ActionArg(msg.action) < argStem) THEN msg.args[argStem] := NIL; END;
retval := noMemory;
i := rxs.LengthArgstring(msg.args[argInput]);
input := rxs.CreateArgstring(msg.args[argInput]^,i+1);
IF input # NIL THEN
input[i] := CHR(0AH); (* LineFeed, needed for ReadArgs() *)
hasOptT := FALSE;
i := ScanArgs(msg.args[argTemplate]^);
rdArgs := d.AllocDosObject(d.rdArgs,NIL);
IF rdArgs # NIL THEN
ol.Allocate(argv, i *SIZE(e.APTR));
IF argv # NIL THEN
rdArgs^ := rdArgsDefault;
rdArgs.source.buffer := y.ADR(input^);
rdArgs.source.length := rxs.LengthArgstring(input);
IF hasOptT THEN
retval := CreateSTEM(msg, msg.args[argTemplate],
y.VAL(ArgsArray,argv),
y.VAL(e.STRPTR,msg.args[argStem]),
TRUE);
END;
arguments := d.ReadArgs(msg.args[argTemplate]^,argv^,rdArgs);
IF arguments = NIL THEN
resultStr := rxs.CreateArgstring(strFALSE,1);
retval := rls.SetRC(msg,d.IoErr());
ELSE
resultStr := rxs.CreateArgstring(strTRUE,1);
retval := CreateSTEM(msg, msg.args[argTemplate],
y.VAL(ArgsArray,argv),
y.VAL(e.STRPTR,msg.args[argStem]),
FALSE);
d.FreeArgs(arguments);
END;
IF resultStr = NIL THEN retval := noMemory; END;
DISPOSE(argv);
END;
d.FreeDosObject(d.rdArgs,rdArgs);
END;
rxs.DeleteArgstring(input);
END;
RETURN retval;
END ReadArgs;
(* ---------------------------------------------------------------- *)
PROCEDURE CheckBinaryVar (msg: rx.RexxMsgPtr;
argNum: INTEGER;
VAR flags: LONGSET): BOOLEAN;
VAR
isBin: BOOLEAN;
BEGIN
IF rls.IsValidArg(msg,argNum,"B",isBin) THEN
IF isBin THEN
flags := flags + LONGSET{d.binaryVar,d.dontNullTerm};
END;
RETURN TRUE;
ELSE
RETURN FALSE;
END;
END CheckBinaryVar;
PROCEDURE CheckLocalGlobal (msg: rx.RexxMsgPtr;
argNum: INTEGER;
VAR flags: LONGSET): BOOLEAN;
BEGIN
IF (rx.ActionArg(msg.action) >= argNum) & (msg.args[argNum] # NIL) THEN
CASE CAP(msg.args[argNum][0]) OF
|"G": INCL(flags,d.globalOnly);
|"L": INCL(flags,d.localOnly);
ELSE
RETURN FALSE;
END;
END;
RETURN TRUE;
END CheckLocalGlobal;
(****** rexxdossupport.library/GetVar *******************
*
* NAME
* GetVar -- Returns the value of a local or global variable
*
* SYNOPSIS
* string = GetVar( name, ["Local" | "Global"], ["Binary"] )
*
* FUNCTION
* Gets the value of a local or environment variable. It is advised to
* only use ASCII strings inside variables, but not required. This stops
* putting characters into the destination when a \n is hit, unless
* "Binary" is specified. (The \n is not stored in the buffer.)
*
* INPUTS
* name - variable name.
* "Global" - tries to get a global env variable.
* "Local" - tries to get a local variable (see note below).
* "Binary" - don't stop at \n
* in this mode the string returned is not null terminated
*
* The default is to try to get a local variable first,
* then to try to get a global environment variable.
*
* RESULT
* string - contents of the variable
*
* RC (rexx variable) - 5 when variable does not exist,
* 0 otherwise
*
* EXAMPLE
* /* */
* username = GetVar("username")
* if RC = 5 then
* say "Variable 'username' is not set"
* else
* say "Variable 'username' is" username
*
* NOTES
* Contents may be max. 512 char.
*
* Since ARexx spawns a new process of each script -- even if
* started from Shell -- option "Local" may not work as supposed.
* But one can
*
* | Callie may | Callie may
* Calling order | read | write
* | callers vars | to callers vars
* ----------------+--------------+-------------------
* Shell -> Arexx | no | no
* ARexx -> Shell | yes | no
* ARexx -> Arexx | no | no
*
* BUGS
* Due to a bug in dos.library, binary global vars will be null
* terminated in V37, V38.
*
* SEE ALSO
* SetVar(), DeleteVar(), dos.library/GetVar()
*
**********************)
PROCEDURE GetVar (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
flags: LONGSET;
len: LONGINT;
res: INTEGER;
buffer: ARRAY 512 OF CHAR;
CONST
argName = 1; argLocGlob = 2; argBinary = 3;
BEGIN
flags := LONGSET{};
IF ~ CheckLocalGlobal(msg,argLocGlob,flags)
OR ~ CheckBinaryVar(msg,argBinary,flags)
OR (msg.args[argName] = NIL) THEN
RETURN invalidArg;
END;
len := d.GetVar(msg.args[argName]^,buffer,SIZE(buffer),flags);
IF len < 0 THEN
RETURN rls.SetRC5(msg);
END;
IF (len > SIZE(buffer)-1) & (len # d.IoErr()) THEN
RETURN stringTooLong;
END;
resultStr := rxs.CreateArgstring(buffer,len);
IF resultStr = NIL THEN RETURN noMemory; END;
RETURN rls.SetRC0(msg);
END GetVar;
(****** rexxdossupport.library/SetVar *******************
*
* NAME
* SetVar -- Sets a local or environment variable
*
* SYNOPSIS@{ub}
* success = SetVar( name, ["Local" | "Global"] )
*
* FUNCTION
* Sets a local or environment variable. It is advised to only use
* ASCII strings inside variables, but not required.
*
* INPUTS
* name - variable name.
* "Global" - tries to get a global env variable.
* "Local" - tries to get a local variable (see note below).
*
* The default is to set a local environment variable.
*
* RESULT
* success - If non-zero, the variable was sucessfully set, FALSE
* indicates failure.
*
* NOTES
* Since ARexx spawn a new process of each script -- even if
* started from Shell -- option "Local" may not work as supposed.
*
* SEE ALSO
* GetVar(), DeleteVar(), dos.library/SetVar()
*
**************************)
PROCEDURE SetVar (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
flags: LONGSET;
CONST
argName = 1; argContents = 2; argLocGlob = 3;
BEGIN
flags := LONGSET{};
IF ~ CheckLocalGlobal(msg,argLocGlob,flags)
OR (msg.args[argName] = NIL) THEN
RETURN invalidArg;
END;
IF d.SetVar(msg.args[argName]^,msg.args[argContents]^,
rxs.LengthArgstring(msg.args[argContents]),flags) THEN
resultStr := rxs.CreateArgstring(strTRUE,1);
ELSE
resultStr := rxs.CreateArgstring(strFALSE,1);
END;
IF resultStr = NIL THEN RETURN noMemory; END;
RETURN rx.ok;
END SetVar;
(****** rexxdossupport.library/DeleteVar *******************
*
* NAME
* DeleteVar -- Deletes a local or environment variable
*
* SYNOPSIS
* success = DeleteVar( name, [ "Local" | "Global" ] )
*
* FUNCTION
* Deletes a local or environment variable.
*
* INPUTS
* name - variable name. Note variable names follow
* filesystem syntax and semantics.
* "Global" - tries to get a global env variable.
* "Local" - tries to get a local variable (see note below).
*
* The default is to delete a local variable if found, otherwise
* a global environment variable if found.
*
* RESULT
* success - If TRUE, the variable was sucessfully deleted,
* FALSE indicates failure.
*
* NOTES
* Since ARexx spawn a new process of each script -- even if
* started from Shell -- option "Local" may not work as supposed.
*
* SEE ALSO
* GetVar(), SetVar(), dos.library/DeleteVar()
*
***********************)
PROCEDURE DeleteVar (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
flags: LONGSET;
CONST
argName = 1; argLocGlob = 2;
BEGIN
flags := LONGSET{};
IF ~ CheckLocalGlobal(msg,argLocGlob,flags)
OR (msg.args[argName] = NIL) THEN
RETURN invalidArg;
END;
IF d.DeleteVar(msg.args[argName]^,flags) THEN
resultStr := rxs.CreateArgstring(strTRUE,1);
ELSE
resultStr := rxs.CreateArgstring(strFALSE,1);
END;
IF resultStr = NIL THEN RETURN noMemory; END;
RETURN rx.ok;
END DeleteVar;
(* ---------------------------------------------------------------- *)
(****** rexxdossupport.library/Fault *******************
*
* NAME
* Fault -- Returns the text associated with a DOS error code
*
* SYNOPSIS
* string = Fault( code, header )
*
* FUNCTION
* This routine obtains the error message text for the given
* error code. The header is prepended to the text of the error
* message, followed by a colon. By convention, error messages
* should be no longer than 80 characters, and preferably no
* more than 60.
*
* The value returned by IoErr() (not available in this library)
* is set to the code passed in. If there is no message for the
* error code, the message will be "Error code <number>\n".
*
* The string will be empty if the code passed in was 0.
*
* INPUTS
* code - Error code
* header - header to output before error text
*
* RESULT
* string - error massage as described above.
*
* RC (rexx variable) - 5 when error message is empty
* 0 otherwise
*
* BUGS
* I've been told that this function returns only an empty sting.
* Since nobody gave me further information, I can't fix it.
*
* SEE ALSO
* dos.library/Fault(), dos.library/IoErr()
*
*****************************)
PROCEDURE Fault (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
CONST
argNumber = 1; argHeader = 2;
VAR
errCode, len: LONGINT;
retval: INTEGER;
buffer: ARRAY 512 OF CHAR; (* should be enough *)
BEGIN
IF (msg.args[argNumber] = NIL) THEN RETURN invalidArg; END;
retval := rx.ok;
IF (rx.ActionArg(msg.action) < argHeader) THEN
msg.args[argHeader] := NIL; END;
len := d.StrToLong(msg.args[argNumber]^, errCode);
IF len # str.Length(msg.args[argNumber]^) THEN
RETURN invalidArg; END;
(* $NilChk- avoid trapping msg.args[argHeader]^ *)
len := d.Fault(errCode, msg.args[argHeader]^, buffer, SIZE(buffer));
(* $NilChk= *)
IF len = 0 THEN
retval := rls.SetRC5(msg);
ELSE
retval := rls.SetRC0(msg);
resultStr := rxs.CreateArgstring(buffer,str.Length(buffer));
IF resultStr = NIL THEN RETURN noMemory; END;
END;
RETURN retval
END Fault;
(* ---------------------------------------------------------------- *)
(****** rexxdossupport.library/MatchPattern *******************
*
* NAME
* MatchPattern -- Checks for a pattern match with a string
*
* SYNOPSIS
* match = MatchPattern(pattern, string, ["Nocase"], ["Parsed"] )
*
* FUNCTION
* Checks for a pattern match with a string.
* This routine is case-sensitive by default. Use option
* "NoCase" for case-insensitve matching.
*
* Use option "Parsed" to indicate that pattern has already been
* tokenized using ParsePattern(). Make sure to use or use not
* "NoCase" for both function.
*
* INPUTS
* pattern - pattern string to match
* string - string to match against given pattern
* "Nocase" - match should be case-insensitve
* "Parsed" - pattern has already been parsed using ParsePattern()
*
* RESULT
* match - success or failure of pattern match.
*
* SEE ALSO
* ParsePattern(), dos.library/MatchPattern(),
* dos.library/MatchPatternNoCase()
*
***********************)
PROCEDURE MatchPattern (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
buffer: e.LSTRPTR;
res, noCase, isParsed: BOOLEAN;
bufferLen: LONGINT;
CONST
argPattern = 1; argInput = 2; argNoCase = 3; argIsParsed = 4;
BEGIN
IF ~ rls.IsValidArg(msg,argNoCase,"N",noCase)
OR ~ rls.IsValidArg(msg,argIsParsed,"P",isParsed)
OR ~ rls.ArgsPresent(msg,argPattern,argInput) THEN
RETURN invalidArg; END;
IF isParsed THEN
buffer := msg.args[argPattern];
res := TRUE;
ELSE
bufferLen := 2 * str.Length(msg.args[argPattern]^) +2;
ol.Allocate(buffer,bufferLen);
IF buffer = NIL THEN
RETURN noMemory;
END;
IF noCase THEN
res := (d.ParsePatternNoCase(msg.args[argPattern]^,buffer^,bufferLen) >= 0);
ELSE
res := (d.ParsePattern(msg.args[argPattern]^,buffer^,bufferLen) >= 0);
END;
IF ~ res THEN
DISPOSE(buffer);
RETURN invalidTemplate;
END;
END;
IF noCase THEN res := d.MatchPatternNoCase(buffer^,msg.args[argInput]^);
ELSE res := d.MatchPattern(buffer^,msg.args[argInput]^); END;
IF ~ isParsed THEN DISPOSE(buffer); END;
IF ~ res THEN
IF d.IoErr() = 0 THEN
resultStr := rxs.CreateArgstring(strFALSE,1);
IF resultStr = NIL THEN RETURN noMemory; END;
RETURN rx.ok;
ELSE
RETURN nestingLevel;
END;
ELSE
resultStr := rxs.CreateArgstring(strTRUE,1);
IF resultStr = NIL THEN RETURN noMemory; END;
RETURN rx.ok;
END;
END MatchPattern;
(****** rexxdossupport.library/ParsePattern *******************
*
* NAME
* ParsePattern -- Create a tokenized string for MatchPattern()
*
* SYNOPSIS
* token = ParsePattern( pattern, ["NoCase"] )
*
* FUNCTION
* Tokenizes a pattern, for use by MatchPattern(). Also indicates
* if there are any wildcards in the pattern (i.e. whether it might match
* more than one item).
*
* For a description of the wildcards, see dos.library/ParsePattern().
*
* INPUTS
* pattern - unparsed wildcard string to search for.
*
* RESULT
* token - output string, tokenized version of input.
*
* RC (rexx variable) - 5 when does not contain wildcards
* 0 otherwise
*
* BUGS
* Since is't not clear wether the resulting token may contain
* null charakters, the returned string is always
* 2 * Length(pattern) + 2 bytes long.
*
* SEE ALSO
* ParsePattern(), dos.library/ParsePattern(),
* dos.library/ParsePatternNoCase()
*
*********************)
PROCEDURE ParsePattern (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
result: INTEGER;
noCase: BOOLEAN;
buffer: e.LSTRPTR;
bufferLen: LONGINT;
CONST
argPattern = 1; argNoCase = 2;
BEGIN
IF ~ rls.IsValidArg(msg,argNoCase,"N",noCase)
OR (msg.args[argPattern] = NIL) THEN
RETURN invalidArg; END;
bufferLen := 2 * str.Length(msg.args[argPattern]^) +2;
ol.Allocate(buffer,bufferLen);
IF buffer = NIL THEN
RETURN noMemory;
END;
IF noCase THEN
result := d.ParsePatternNoCase(msg.args[argPattern]^,buffer^,bufferLen)
ELSE
result := d.ParsePattern(msg.args[argPattern]^,buffer^,bufferLen);
END;
IF result < 0 THEN
result := invalidTemplate;
ELSE
resultStr := rxs.CreateArgstring(buffer^,str.Length(buffer^));
IF resultStr = NIL THEN
result := noMemory;
ELSIF result > 0 THEN
result := rls.SetRC0(msg);
ELSE
result := rls.SetRC5(msg);
END;
END;
DISPOSE(buffer);
RETURN result;
END ParsePattern;
(* ---------------------------------------------------------------- *)
(****** rexxdossupport.library/Delete *******************
*
* NAME
* Delete -- Delete a file or directory (V2)
*
* SYNOPSIS
* success = Delete( name )
*
* FUNCTION
* This attempts to delete the file or directory specified by
* 'name'. If the deletion fails an error is returned and the
* rexx variable RC is set. Note that all the files within a
* directory must be deleted before the directory itself can be
* deleted.
*
* INPUTS
* name - name of file or directory to delete.
*
* RESULT
* success - If TRUE, the file was sucessfully deleted,
* FALSE indicates failure.
*
* RC (rexx variable) - contains the dos error code if the
* function was not successfull. This can can directly
* be used as input for Fault().
*
* SEE ALSO
* Fault(), dos.library/DeleteFile()
*
****************************)
PROCEDURE Delete (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
CONST
argName = 1;
VAR
retval: INTEGER;
BEGIN
IF msg.args[argName] = NIL THEN RETURN invalidArg; END;
retval := rx.ok;
IF d.DeleteFile(msg.args[argName]^) THEN
resultStr := rxs.CreateArgstring(strTRUE,1);
ELSE
resultStr := rxs.CreateArgstring(strFALSE,1);
retval := rls.SetRC(msg,d.IoErr());
END;
IF resultStr = NIL THEN retval := noMemory; END;
RETURN retval;
END Delete;
(****** rexxdossupport.library/Rename *******************
*
* NAME
* Rename -- Rename a directory or file (V2)
*
* SYNOPSIS
* success = Rename( oldName, newName )
*
* FUNCTION
* Rename() attempts to rename the file or directory specified
* as 'oldName' with the name 'newName'. If the file or
* directory 'newName' exists, Rename() fails and returns an
* error. Both 'oldName' and the 'newName' can contain a
* directory specification. In this case, the file will be moved
* from one directory to another.
*
* Note: it is impossible to Rename() a file from one volume to
* another.
*
* INPUTS
* oldName - pointer to a null-terminated string
* newName - pointer to a null-terminated string
*
* RESULT
* success - If TRUE, the variable was sucessfully deleted,
* FALSE indicates failure.
*
* RC (rexx variable) - contains the dos error code if the
* function was not successfull. This can can directly
* be used as input for Fault().
*
* SEE ALSO
* Fault(), dos.library/Rename()
*
***************************)
PROCEDURE Rename (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
retval: INTEGER;
CONST
argFrom = 1; argTo = 2;
BEGIN
IF ~ rls.ArgsPresent(msg,argFrom,argTo) THEN RETURN invalidArg; END;
retval := rx.ok;
IF d.Rename(msg.args[argFrom]^, msg.args[argTo]^) THEN
resultStr := rxs.CreateArgstring(strTRUE,1);
ELSE
resultStr := rxs.CreateArgstring(strFALSE,1);
retval := rls.SetRC(msg,d.IoErr());
END;
IF resultStr = NIL THEN retval := noMemory; END;
RETURN retval;
END Rename;
(****** rexxdossupport.library/MakeDir *******************
*
* NAME
* MakeDir -- Create a new directory (V2)
*
* SYNOPSIS
* success = MakeDir( name )
*
* FUNCTION
* MakeDir creates a new directory with the specified name. If
* it fails an error is returned and the rexx variable RC is
* set. Directories can only be created on devices which
* support them, e.g. disks.
*
* INPUTS
* name - name of directory to create
*
* RESULT
* success - If TRUE, the variable was sucessfully deleted,
* FALSE indicates failure.
*
* RC (rexx variable) - contains the dos error code if the
* function was not successfull. This can can directly
* be used as input for Fault().
*
* SEE ALSO
* Fault(), dos.library/CreateDir()
*
**************************)
PROCEDURE MakeDir (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
retval: INTEGER;
CONST
argName = 1;
VAR
dir: d.FileLockPtr;
BEGIN
IF msg.args[argName] = NIL THEN RETURN invalidArg; END;
retval := rx.ok;
dir := d.CreateDir(msg.args[argName]^);
IF dir # NIL THEN
d.UnLock(dir);
resultStr := rxs.CreateArgstring(strTRUE,1);
ELSE
resultStr := rxs.CreateArgstring(strFALSE,1);
retval := rls.SetRC(msg,d.IoErr());
END;
IF resultStr = NIL THEN retval := noMemory; END;
RETURN retval;
END MakeDir;
(****** rexxdossupport.library/SetComment *******************
*
* NAME
* SetComment -- Change a files' comment string (V2)
*
* SYNOPSIS
* success = SetComment( name, comment )
*
* FUNCTION
* SetComment() sets a comment on a file or directory. The
* comment may be up to 80 characters in the current ROM
* filesystem (and RAM:). Note that not all filesystems will
* support comments (for example, NFS usually will not), or the
* size of comment supported may vary.
*
* INPUTS
* name - name of file or directory to set comment
* comment - comment to be set
*
* RESULT
* success - If TRUE, the variable was sucessfully deleted,
* FALSE indicates failure.
*
* RC (rexx variable) - contains the dos error code if the
* function was not successfull. This can can directly
* be used as input for Fault().
*
* SEE ALSO
* SetProtection(), Fault(), dos.library/SetComment()
*
**************************)
PROCEDURE SetComment (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
retval: INTEGER;
CONST
argFile = 1; argComment = 2;
BEGIN
IF ~ rls.ArgsPresent(msg,argFile,argComment) THEN RETURN invalidArg; END;
retval := rx.ok;
IF d.SetComment(msg.args[argFile]^, msg.args[argComment]^) THEN
resultStr := rxs.CreateArgstring(strTRUE,1);
ELSE
resultStr := rxs.CreateArgstring(strFALSE,1);
retval := rls.SetRC(msg,d.IoErr());
END;
IF resultStr = NIL THEN retval := noMemory; END;
RETURN retval;
END SetComment;
(****** rexxdossupport.library/SetProtection *******************
*
* NAME
* SetProtection -- Set protection for a file or directory (V2)
*
* SYNOPSIS
* success = SetProtection( name, mask )
*
* FUNCTION
* SetProtection() sets the protection attributes on a file or
* directory. See <dos/dos.h> for a listing of protection bits.
*
* The archive bit should be cleared by the filesystem whenever
* the file is changed. Backup utilities will generally set the
* bit after backing up each file.
*
* The V36 Shell looks at the execute bit, and will refuse to
* execute a file if it is set.
*
* Other bits will be defined in the <dos/dos.h>include files.
* Rather than referring to bits by number you should use the
* definitions in <dos/dos.h>.
*
* INPUTS
* name - name of file or directory to set protection
* mask - the protection mask required
*
* RESULT
* success - If TRUE, the variable was sucessfully deleted,
* FALSE indicates failure.
*
* RC (rexx variable) - contains the dos error code if the
* function was not successfull. This can can directly
* be used as input for Fault().
*
* SEE ALSO
* SetComment(), Fault(), dos.library/SetProtection()
*
**************************)
PROCEDURE SetProtection (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
retval: INTEGER;
CONST
argFile = 1; argFlags = 2;
TYPE
LONGSETPtr = UNTRACED POINTER TO LONGSET;
BEGIN
IF ~ rls.ArgsPresent(msg,argFile,argFlags)
OR (rxs.LengthArgstring(msg.args[argFlags]) # 4)
THEN RETURN invalidArg; END;
retval := rx.ok;
IF d.SetProtection(msg.args[argFile]^,y.VAL(LONGSETPtr,msg.args[argFile])^) THEN
resultStr := rxs.CreateArgstring(strTRUE,1);
ELSE
resultStr := rxs.CreateArgstring(strFALSE,1);
retval := rls.SetRC(msg,d.IoErr());
END;
IF resultStr = NIL THEN retval := noMemory; END;
RETURN retval;
END SetProtection;
(****** rexxdossupport.library/AbsolutePath *******************
*
* NAME
* AbsolutePath -- Returns the fully qualified path of a file or dir (V3)
*
* SYNOPSIS
* path = AbsolutePath( name )
*
* FUNCTION
* Determines the absolute path of a file or directory.
*
* INPUTS
* name - file or directory name
*
* RESULT
* path - absolute path to file/dir
*
* RC (rexx variable) - 5 when file does not exist,
* 0 otherwise
*
* EXAMPLE
* /* */
* path = AbsolutePath(":s/Startup-Sequence")
* if RC = 5 then
* say "File ':s/Startup-Sequence' does not exist"
* else
* say "':s/Startup-Sequence' is '" || path || "'"
*
* SEE ALSO
* dos.library/NameFromLock()
*
**********************)
PROCEDURE AbsolutePath (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
len: LONGINT;
res: BOOLEAN;
lock: d.FileLockPtr;
buffer: ARRAY 512 OF CHAR;
CONST
argName = 1;
BEGIN
lock := d.Lock(msg.args[argName]^, d.sharedLock);
IF lock = NIL THEN RETURN rls.SetRC5(msg) END;
res := d.NameFromLock(lock, buffer, SIZE(buffer));
d.UnLock(lock); lock := NIL;
IF ~ res THEN RETURN rls.SetRC5(msg) END;
resultStr := rxs.CreateArgstring(buffer,str.Length(buffer));
IF resultStr = NIL THEN RETURN noMemory; END;
RETURN rls.SetRC0(msg);
END AbsolutePath;
(****** rexxdossupport.library/AddPart *******************
*
* NAME
* AddPart -- Appends a file/dir to the end of a path (V3)
*
* SYNOPSIS
* newpath = AddPart( dirname , filename )
*
* FUNCTION
* This funktion adds a file, directory, or subpath name to a
* directory path name taking into account any required
* seperator charakters.
*
* INPUTS
* dirname - the path to add a fir/directory name to.
* filename - the filename or directory name to add.
*
* RESULT
* newpath - resulting path.
*
* RC (rexx variable) - 5 when file does not exist,
* 0 otherwise
*
* EXAMPLE
* /* */
* path = AddPart("System:s/","Startup-Sequence")
* if RC = 0 then say path
* /* --> System:s/Startup-Sequence */
*
* path = AddPart("System:s/bla",":Startup-Sequence")
* if RC = 0 then say path
* /* --> System:Startup-Sequence */
*
* path = AddPart("System:s/bla","/Startup-Sequence")
* if RC = 0 then say path
* /* --> System:s/bla//Startup-Sequence */
*
* BUGS
* Neither the input dirname nor the resulting path must exceed
* 511 Bytes. If a string overflow occurrs, error 'string too
* long' will be returned which ARexx outputs as 'string > 65535
* charakters'.
*
* SEE ALSO
* dos.library/AddPart(), FilePart(), PathPart()
*
**********************)
PROCEDURE AddPart (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
buffer: ARRAY 512 OF CHAR;
CONST
argDir = 1; argFile = 2;
BEGIN
IF str.Length(msg.args[argDir]^) >= SIZE(buffer) THEN
RETURN stringTooLong END;
COPY(msg.args[argDir]^, buffer);
IF ~ d.AddPart(buffer, msg.args[argFile]^, SIZE(buffer)) THEN
RETURN stringTooLong END;
resultStr := rxs.CreateArgstring(buffer, str.Length(buffer));
IF resultStr = NIL THEN RETURN noMemory; END;
RETURN rls.SetRC0(msg);
END AddPart;
(****** rexxdossupport.library/FilePart *******************
*
* NAME
* FilePart -- Returns the last component of a path (V3)
*
* SYNOPSIS
* part = FilePart( path )
*
* FUNCTION
* This function returns the last component of a string path
* specification, which will normally be the file name. If there is
* only one component, it returns the complete string.
*
* INPUTS
* path - pointer to an path string. May be relative to the current
* directory or the current disk.
*
* RESULT
* part - resulting path part.
*
* EXAMPLE
* /* */
* say FilePart("xxx:yyy/zzz/qqq")
* /* --> qqq */
* say FilePart("xxx:yyy")
* /* --> yyy */
*
* SEE ALSO
* dos.library/FilePart(), AddPart(), PathPart()
*
**********************)
PROCEDURE FilePart (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
filePart: e.LSTRPTR;
CONST
argPath = 1;
BEGIN
filePart := d.FilePart(msg.args[argPath]^);
resultStr := rxs.CreateArgstring(filePart^,str.Length(filePart^));
IF resultStr = NIL THEN RETURN noMemory END;
RETURN rls.SetRC0(msg);
END FilePart;
(****** rexxdossupport.library/PathPart *******************
*
* NAME
* PathPart -- Strips the next-to-last component of a path. (V3)
*
* SYNOPSIS
* part = PathPart( path )
*
* FUNCTION
* This function strips the next-to-last component of a path
* specification, which will normally result in the directory name.
* If there is only one component, it returns an empty string.
*
* INPUTS
* path - path string. May be relative to the current directory or
* the current disk.
*
* RESULT
* part - resulting path part.
*
* EXAMPLE
* /* */
* say FilePart("xxx:yyy/zzz/qqq")
* /* --> xxx:yyy/zzz */
* say FilePart("xxx:yyy")
* /* --> xxx: */
*
* SEE ALSO
* dos.library/PathPart(), AddPart(), FilePart()
*
**********************)
PROCEDURE PathPart (msg: rx.RexxMsgPtr; VAR resultStr: e.LSTRPTR): INTEGER;
VAR
fullPath, pathPart: e.LSTRPTR;
len: LONGINT;
CONST
argPath = 1;
BEGIN
fullPath := msg.args[argPath];
pathPart := d.PathPart(fullPath^);
len := PointerArithmetics.Subtract(pathPart,fullPath);
resultStr := rxs.CreateArgstring(fullPath^,len);
IF resultStr = NIL THEN RETURN noMemory END;
RETURN rls.SetRC0(msg);
END PathPart;
(* ---------------------------------------------------------------- *)
PROCEDURE Dispatch * (msg{8}: rx.RexxMsgPtr): LONGINT; (* $SaveRegs+ *)
VAR
resultStr: e.LSTRPTR;
retval: LONGINT;
BEGIN
ol.SetA5();
retval := rls.Dispatch(msg,resultStr,functionList);
y.SETREG(8,resultStr);
RETURN retval;
END Dispatch;
BEGIN
IF (rxs.base = NIL) OR (d.base.lib.version < 37) THEN HALT(20); END;
END rexxdossupport.